#include <Bitmap.hpp>
#include <Ray.hpp>
#include <Sphere.hpp>

static glm::vec3 ray_color(const Ray& ray, Hittable* world) {
  HitRecord rec;

  if (world->Hit(ray, 0.f, infinity, rec)) {
    return 0.5f * (rec.normal + glm::vec3(1.f, 1.f, 1.f));
  }

  glm::vec3 unit_direction = glm::normalize(ray.Direction());
  float t = 0.5f * (unit_direction.y + 1.f);
  return (1.f - t) * glm::vec3(1.f, 1.f, 1.f) + t * glm::vec3(0.5f, 0.7f, 1.f);
}

int main(int argc, const char** argv) {
  // image
  auto bitmap = Bitmap::CreateBitmap(400, 16.f / 9.f);

  // world
  auto world = std::make_unique<HittableList>();

  world->AddObject(std::make_shared<Sphere>(glm::vec3(0.f, 0.f, -1.f), 0.5f));
  world->AddObject(
      std::make_shared<Sphere>(glm::vec3(0.f, -100.5f, -1.f), 100.f));

  // camera
  float viewport_height = 2.f;
  float viewport_width = bitmap->PixelRadio() * viewport_height;
  auto focal_length = 1.f;

  glm::vec3 origin(0.f, 0.f, 0.f);
  auto horizontal = glm::vec3(viewport_width, 0.f, 0.f);
  auto vertical = glm::vec3(0.f, viewport_height, 0.f);

  auto lower_left_corner = origin - horizontal / 2.f - vertical / 2.f -
                           glm::vec3(0, 0, focal_length);

  for (uint32_t i = 0; i < bitmap->Width(); i++) {
    for (uint32_t j = 0; j < bitmap->Height(); j++) {
      auto u = float(i) / (bitmap->Width() - 1);
      auto v = float(j) / (bitmap->Height() - 1);

      Ray ray(origin,
              lower_left_corner + u * horizontal + v * vertical - origin);

      auto color = ray_color(ray, world.get());

      bitmap->setPixel(i, bitmap->Height() - 1 - j, color);
    }
  }

  bitmap->writeToFile("multi_object.png");
  return 0;
}